home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 00 - Game Programming Primer / HelloWorld1.c next >
Text File  |  1995-06-26  |  14KB  |  314 lines

  1. //==============================================================================================\\
  2. //        -----------------------------------------------------------------------------------        \\
  3. //        HelloWorld1.c version 1.0.0    copyright © 1993…1995 Jamie McCornack, john calhoun            \\
  4. //        -----------------------------------------------------------------------------------        \\
  5. //         Demo program for Macintosh GameWriter 1.0.0, a training program…                        \\
  6. //        …for beginning Mac game programmers. MGW1 includes MGWExterns1.h, MGWUtilities1.c,…        \\
  7. //        …MGWSound1.c, MGWGraphics1.c, MGWGraphicsBWLite1.c, HelloWorld.rsrc and an assortment…    \\
  8. //        …of demo programs; projects HelloWorld1.π etc. and source code files HelloWorld1.c etc.    \\
  9. //         A tutorial is available in Tricks of the Mac Game Programming Gurus, published…        \\
  10. //        …by Hayden Books, August 1995.                                                            \\
  11. //                                                                                                \\
  12. //        This code is offered by the copyright holders for no fee and for whatever use…            \\
  13. //        …you care to make of it, but we do hope you remember where it came from.                \\
  14. //                                                                                                \\
  15. //        Please send bug reports to MacGameDev at America Online.    macgamedev@aol.com            \\
  16. //        Suggestions and observations are also appreciated.                                        \\
  17. //        Updates and upgrades will be available now and then from the above e-mail address.        \\
  18. //==============================================================================================\\
  19.  
  20. // This program opens a window, displays a black and white background, and at first…
  21. // …mouseclick, runs a clam across the screen. At second mouseclick, the clam stops,…
  22. // …talks, and flaps its/his/her face for 40 frames. Then the program quits.
  23.  
  24.  
  25. #include "MGWExterns1.h"
  26.  
  27. #define     kPutInFront    (WindowPtr)-1L
  28. #define     kWaitTicks     4L    // Sets the delay in Ticks between frames. Try 3. Try 2. Try 0.
  29. #define     kStepLength    14    // Sets the distance in pixels between sprite moves.
  30. #define  kFrontFace        0
  31. #define  kBlinkFace     1
  32. #define  kEehFace        2
  33. #define  kOohFace        3
  34. #define  kStepRightFace    4
  35. #define  kWalkRightFace    5
  36. #define  kRunRightFace    6
  37. #define  kMaxFaces        7
  38.                 // The resource constants--with 'r' prefix like Apple wants them.}
  39. #define  rFacesID        129        // The 'PICT' ID# where the views of the clam are located.}
  40. #define  rMasksID        130        // The 'PICT' ID# where the clam masks are located.}
  41. #define  rBackgroundID    128    // The 'PICT' ID# where the background picture is located.}
  42. #define  rMainWindowID    128    // The 'WIND' resource ID# for the main window.}
  43.  
  44. #define  rHelloSndID    3000
  45. #define  rFootstepSndID    3001
  46. #define  rImpactSndID    3002
  47. #define  rDizzySndID    3003
  48.     
  49. typedef struct
  50. {
  51.     Rect    face;
  52.     Rect    mask;
  53. } tSpriteType;
  54.  
  55.  
  56. Rect    bigPictureRect, facesRect, masksRect, clamIsAtRect, clamWasAtRect, clamComboRect;
  57. GrafPtr    workPort, facesPort, masksPort, backgroundPort, mainWindow;
  58. Boolean    itWorked;
  59. long    targetTick;
  60. short        thisSprite, thisFaceCounter;
  61.  
  62. tSpriteType    sprite[kMaxFaces];
  63.     
  64. extern    Boolean        gUserWantsSound;
  65.     
  66. //==============================================================  Prototypes
  67.  
  68. void InitAll(void);
  69. void OpenMainWindow (void);
  70. void SetTheRects(void);
  71. void SetThePorts(void);
  72. void ShowClam (void);
  73. void DoDelay (void);
  74. void RunRight (void);
  75. void LipSynch (void);
  76.  
  77. //==============================================================  Functions
  78.  
  79. //--------------------------------------------------------------  InitAll
  80.  
  81. void InitAll(void)
  82. {
  83.     InitToolbox();
  84.     gUserWantsSound = TRUE;
  85.     InitializeForSound();
  86.     SetTheRects();        // Since some of these Rects define fields in GrafPorts, set the rects…
  87.     SetThePorts();        // …before setting the ports.
  88.     thisSprite = kFrontFace;
  89.     thisFaceCounter = 0;
  90.     targetTick = TickCount() + kWaitTicks;
  91. }
  92.  
  93. //--------------------------------------------------------------  OpenMainWindow
  94.  
  95. void OpenMainWindow (void)
  96. {
  97.     mainWindow = GetNewCWindow(128, 0L, kPutInFront);    // Load window from resource.
  98.     ShowWindow((GrafPtr)mainWindow);                    // Now display it.
  99.     SetPort((GrafPtr)mainWindow);                        // Make its port current.
  100.     ClipRect(&bigPictureRect);                            // Set its clip region.
  101.     CopyRgn(mainWindow->clipRgn, mainWindow->visRgn);    // Set its visRgn.
  102.     ForeColor(blackColor);                                // Set its pen color to black.
  103.     BackColor(whiteColor);                                // Set background color white.
  104. }
  105.  
  106. //--------------------------------------------------------------  SetTheRects
  107.  
  108. void SetTheRects(void)    // The most tedious part of programming this type of game.
  109. {
  110.     SetRect(&facesRect, 0, 0, 448, 64);        // Size and shape of BitMap for the sprite faces.
  111.     SetRect(&masksRect, 0, 0, 448, 32);        // Size and shape of BitMap for the sprite masks.
  112.     SetRect(&bigPictureRect, 0, 0, 512, 322);    // The shape of the picture we'll put in the main window, workPort and backgroundPort.}
  113.     SetRect(&clamIsAtRect, 200, 244, 232, 276);    // The shape (32 x 32) of the images of Clem, and the position of the first image.}
  114.     clamWasAtRect = clamIsAtRect;                // Initializing clamIsAtRect...it has to start somewhere, and this is handy.}
  115.     clamComboRect = clamIsAtRect;
  116.         // And now, the tedium. In this sample, all we're doing is showing the clam running across the screen to the right.}
  117.         // However, if you use ResEdit and look at 'PICT' 129 in Sample.rsrc, you'll find 28 different views of the clam.}
  118.         // If we wanted the clam to run left too, and walk slowly, and face the user, and blink its eyes, we'd be calling…}
  119.         // …SetRect 56 times--one face and one mask per sprite. And if we had jumping clams and rear views of clams…}
  120.         // …and starfish and clamdiggers and other hazards of the clam environment, we might have hundreds of rects to set.}
  121.     SetRect(&sprite[kFrontFace].face, 320, 32, 352, 64);    // The shape and position of sprite[kFrontFace].face on facesPort.portBits.
  122.     SetRect(&sprite[kFrontFace].mask, 320, 0, 352, 32);    // The shape and position of sprite[kFrontFace].mask on masksPort.portBits.
  123.     SetRect(&sprite[kBlinkFace].face, 320, 0, 352, 32);    // Note that some faces (e.g. eyes open or closed) use the same mask,…
  124.     SetRect(&sprite[kBlinkFace].mask, 320, 0, 352, 32);    // …since they have the same silhouette.}
  125.     SetRect(&sprite[kEehFace].face, 352, 0, 384, 32);    // I could write more comments here, but setting these rects…
  126.     SetRect(&sprite[kEehFace].mask, 352, 0, 384, 32);    // …is already tedious enough without a bunch of busy-work.
  127.     SetRect(&sprite[kOohFace].face, 352, 32, 384, 64);
  128.     SetRect(&sprite[kOohFace].mask, 352, 0, 384, 32);    
  129.     SetRect(&sprite[kStepRightFace].face, 192, 0, 224, 32);    
  130.     SetRect(&sprite[kStepRightFace].mask, 192, 0, 224, 32);    
  131.     SetRect(&sprite[kWalkRightFace].face, 224, 0, 256, 32);    
  132.     SetRect(&sprite[kWalkRightFace].mask, 224, 0, 256, 32);    
  133.     SetRect(&sprite[kRunRightFace].face, 160, 0, 192, 32);    // BTW, there are plenty more clam faces and masks in the 'PICT's,…
  134.     SetRect(&sprite[kRunRightFace].mask, 160, 0, 192, 32);    // …if you feel you need rect setting practice.  :-)
  135. }
  136.  
  137. //--------------------------------------------------------------  SetThePorts
  138.  
  139. void SetThePorts(void)    // Create the GrafPorts and load their .portBits fields.
  140. {
  141.             // Create BitMap for sprite faces.
  142.     CreateOffScreenBitMapLite (&facesRect, &facesPort);
  143.     LoadGraphicLite (rFacesID);        // …load 'PICT' resource for the clam faces.}
  144.  
  145.             // Create BitMap for sprite masks.
  146.     CreateOffScreenBitMapLite (&masksRect, &masksPort);
  147.     LoadGraphicLite (rMasksID);        // …load 'PICT' resource for the masks of the clam.}
  148.  
  149.             // Create BitMap for background picture.
  150.     CreateOffScreenBitMapLite (&bigPictureRect, &backgroundPort);
  151.     LoadGraphicLite(rBackgroundID);    // …load 'PICT' resource for the background picture.}
  152.  
  153.             // Create BitMap for off-screen assembly of images.
  154.     CreateOffScreenBitMapLite (&bigPictureRect, &workPort);
  155.  
  156.     OpenMainWindow();
  157.  
  158.         //{This fills the main window with the background picture, so the user can see it.
  159.     CopyBits(&((GrafPtr)backgroundPort)->portBits,
  160.         &((GrafPtr)mainWindow)->portBits, 
  161.         &bigPictureRect, &bigPictureRect, srcCopy, mainWindow->visRgn);
  162.  
  163. // This fills the workPort.portBits with the background picture, so updates can be done quickly.
  164.     CopyBits(&((GrafPtr)backgroundPort)->portBits,
  165.         &((GrafPtr)workPort)->portBits, 
  166.         &bigPictureRect, &bigPictureRect, srcCopy, mainWindow->visRgn);
  167. }
  168.  
  169. //--------------------------------------------------------------  ShowClam 
  170.  
  171. void ShowClam (void)    // Do the animation and make it appear on the screen.
  172. {
  173.     CopyMask(&((GrafPtr)facesPort)->portBits, 
  174.         &((GrafPtr)masksPort)->portBits, 
  175.         &((GrafPtr)workPort)->portBits, 
  176.         &sprite[thisSprite].face, 
  177.         &sprite[thisSprite].mask, 
  178.         &clamIsAtRect);
  179. // Now there is an image of a clam in the new position in workMap.  If we had done this work in…
  180. // mainWindow, we would have seen considerable flickering.  Instead, we did it offscreen, and left the…
  181. // previous image of the clam visible on the screen while we worked.
  182.  
  183.     UnionRect(&clamWasAtRect, &clamIsAtRect, &clamComboRect);
  184. // Find the smallest rectangle which will cover the old position of the clam and the new.
  185.  
  186.     CopyBits(&((GrafPtr)workPort)->portBits, 
  187.         &(((GrafPtr)mainWindow)->portBits), 
  188.         &clamComboRect, &clamComboRect, srcCopy, mainWindow->visRgn);
  189. // Copy the contents of comboRect from workPort->portBits to the main window. In one swell foop, the old clam…}
  190. //…will be erased, and the new clam overlayed onto the background picture. Wallah! Flicker-free animation!}
  191.  
  192.     CopyBits(&((GrafPtr)backgroundPort)->portBits, 
  193.         &(((GrafPtr)workPort)->portBits), 
  194.         &clamIsAtRect, &clamIsAtRect, srcCopy, mainWindow->visRgn);
  195. // Restore the workPort by covering up our clam with the background it obscures.
  196. // This way, workPort->portBits is identical to backgroundPort->portBits,…
  197. // without having to copy the entire BitMap.
  198. }
  199.  
  200. //--------------------------------------------------------------  DoDelay
  201.  
  202. // This is the companion function to the above function (LogNextTick()).
  203. // We do nothing but loop until TickCount() catches up with (or passes) our…
  204. // global variable tickNext.
  205.  
  206. void DoDelay (void)
  207. {
  208.     do
  209.     {
  210.     }
  211.     while (TickCount() < targetTick);            // Loop until TickCount() catches up.
  212.     targetTick = TickCount() + kWaitTicks;
  213. }
  214. //--------------------------------------------------------------  RunRight
  215.  
  216. void RunRight (void)    //Gives a sequence of views of the clam running to the right.
  217. {
  218.     switch    (thisSprite)                    //If the current view of the clam is…
  219.     {    case    (kStepRightFace):             // …kStepRightFace, then set thisSprite to…
  220.         {    thisSprite = kWalkRightFace;    // …kWalkRightFace, and if it is currently…
  221.             break;    }
  222.         case    (kWalkRightFace):             // …kWalkFace, then set it to…
  223.         {    thisSprite = kRunRightFace;        // …kRunRightFace.
  224.             PlayASound(rFootstepSndID, kHighestSoundPriority);    // Note sound priority.
  225.             break;    }
  226.     // And if it was neither kStepRightFace nor kWalkRightFace, then thisSprite was either…
  227.         default                    :             // …kRunRightFace, or what it was when RunRight()…
  228.             thisSprite = kStepRightFace;    // …was called, so we set it to kStepRightFace
  229.     }
  230.     clamWasAtRect = clamIsAtRect;            // Store the clam's current position as its last position,…
  231.                                             // …we'll be erasing it next time through the loop.
  232.     OffsetRect(&clamIsAtRect, kStepLength, 0);    // Set the clam's next position--it'll be…
  233.                                             // …kStepLength pixels to the right of its last position.
  234.     if (clamIsAtRect.left > 512)                // If the clam has wandered out of sight,…
  235.     {                                        // …set the right border of clamIsAtRect…
  236.         clamIsAtRect.right = 0;                // …to the left edge of the screen…
  237.         clamIsAtRect.left = -32;            // …and move the left border of clamIsAtRect…
  238.     }                                        // …as needed to maintain its 32 x 32 shape & size.
  239.   ShowClam();                        // The actual animation routine!
  240.   DoDelay();    // Do nothing for a while. In a real game, you'll want to use time more wisely.
  241. }
  242.  
  243. //--------------------------------------------------------------  LipSynch
  244.  
  245. void LipSynch (void)
  246. {
  247.     while (thisFaceCounter < 40)
  248.     {
  249.         thisFaceCounter = thisFaceCounter + 1;
  250.          switch (thisFaceCounter)
  251.          {    case    (2): 
  252.             {    thisSprite = kEehFace;
  253.                 break;    }
  254.             case    (4): 
  255.             {    thisSprite = kFrontFace;
  256.                 break;    }
  257.             case    (5): 
  258.             {    thisSprite = kOohFace;
  259.                 break;    }
  260.             case    (9): 
  261.             {    thisSprite = kEehFace;
  262.                 break;    }
  263.             case    (11): 
  264.             {    thisSprite = kOohFace;
  265.                 break;    }
  266.             case    (13): 
  267.             {    thisSprite = kFrontFace;
  268.                 break;    }
  269.             case    (16): 
  270.             {    thisSprite = kBlinkFace;
  271.                 break;    }
  272.             case    (18): 
  273.             {    thisSprite = kFrontFace;
  274.                 break;    }
  275.             case    (35): 
  276.             {    thisSprite = kBlinkFace;
  277.                 break;    }
  278.             case    (38): 
  279.             {    thisSprite = kFrontFace;
  280.                 break;    }
  281.         }
  282.         ShowClam();
  283.         DoDelay();        // Do nothing for a while, so the lips don't flap too fast.
  284.     }
  285. }
  286.  
  287. //--------------------------------------------------------------  main
  288. //----------------------------------------------------------------------
  289.  
  290. void main(void)
  291. {
  292.     InitAll();
  293.     while (!Button())    // Before the user presses the mouse button, nothing happens.
  294.         {
  295.         }
  296.     while (Button())    // When the user presses the mouse button, nothing happens.
  297.         {
  298.         }
  299.     while (!Button())    // When the mouse button is released, continue to…
  300.         {
  301.         RunRight();        // …show the clam running right (duh),…
  302.         }
  303.     while (Button())    // …until the button is pushed.
  304.         {                // Do nothing until the button is released.
  305.         }
  306.     PlayASound(rHelloSndID, kMediumSoundPriority);
  307.     LipSynch();
  308.     CloseDownSound();
  309. }                        // And we're done.
  310.  
  311. //------------------------------------------------------------------------------------------\\
  312. //                                    End HelloWorld1.c                                        \\
  313. //------------------------------------------------------------------------------------------\\
  314.